﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI;
using System.Reflection;
using System.Web.UI.WebControls;
using System.Globalization;

namespace Normal
{
    /// <summary>
    /// The purpose of this class is to provide some helper functions
    /// to iterate with web context
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class WebHelper<T> where T : class
    {
        private string _dateFormat;

        protected string DateFormat
        {
            get { return _dateFormat; }
            set { _dateFormat = value; }
        }
        private string _numberFormat;

        protected string NumberFormat
        {
            get { return _numberFormat; }
            set { _numberFormat = value; }
        }

        /// <summary>
        /// Creates a WebHelper instance passing the DateFormat and NumberFormat Contants
        /// </summary>
        /// <param name="_dateFormat"></param>
        /// <param name="_numberFormat"></param>
        public WebHelper(string _dateFormat, string _numberFormat)
        {
            NumberFormat = _numberFormat;
            DateFormat = _dateFormat;
        }

        /// <summary>
        /// Creates a WebHelper instance passing the current CultureInfo
        /// </summary>
        /// <param name="ci"></param>
        public WebHelper(CultureInfo ci)
        {
            DateFormat = ci.DateTimeFormat.ShortDatePattern;
            NumberFormat = "F" + ci.NumberFormat.NumberDecimalDigits;
        }

        /// <summary>
        /// Fills the Page Control with the given object
        /// </summary>
        /// <param name="_page">The Web Page Context</param>
        /// <param name="UsedObject"></param>
        public void FillPage(Page _page, T UsedObject)
        {
            List<Control> lstControls = new List<Control>();
            GetElegibleFields(lstControls, _page.Controls);
            List<RequiredFieldValidator> lstValidators = new List<RequiredFieldValidator>();
            GetValidators(lstValidators, _page.Controls);
            foreach (PropertyInfo Info in UsedObject.GetType().GetProperties())
            {
                foreach (object attr in Info.GetCustomAttributes(typeof(Id), true))
                {
                    foreach (Control control in lstControls)
                    {
                        if (Info.Name.Equals(control.ID, StringComparison.OrdinalIgnoreCase))
                        {
                            FillControl(control, UsedObject, Info.Name);
                        }
                    }
                }
                foreach (object attr in Info.GetCustomAttributes(typeof(Column), true))
                {
                    foreach (Control control in lstControls)
                    {
                        if (Info.Name.Equals(control.ID, StringComparison.OrdinalIgnoreCase))
                        {
                            FillControl(control, UsedObject, Info.Name);
                            foreach (RequiredFieldValidator req in lstValidators)
                            {
                                if (req.ControlToValidate.Equals(Info.Name, StringComparison.OrdinalIgnoreCase))
                                {
                                    req.Enabled = ((Column)attr).Required;
                                    req.ErrorMessage = ((Column)attr).MsgRequired;
                                }
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Fill the Control based on Property Name and given Object
        /// </summary>
        /// <param name="control"></param>
        /// <param name="UsedObject"></param>
        /// <param name="PropertyName"></param>
        protected void FillControl(Control control, T UsedObject, string PropertyName)
        {
            object _value = UsedObject.GetType().InvokeMember(PropertyName,
                BindingFlags.GetProperty, null, UsedObject, null);
            if (_value != null)
            {
                if (control is DropDownList)
                {
                    foreach (ListItem item in ((DropDownList)control).Items)
                    {
                        item.Selected = false;
                        if (item.Value.ToString() == _value.ToString())
                        {
                            item.Selected = true;
                        }
                        else if (_value.GetType().GetCustomAttributes(typeof(Table), true).Length > 0)
                        {
                            foreach (PropertyInfo inf in _value.GetType().GetProperties())
                            {
                                if (inf.GetCustomAttributes(typeof(Id), true).Length > 0)
                                {
                                    object _idvalue = _value.GetType().InvokeMember(inf.Name, BindingFlags.GetProperty, null, _value, null);
                                    if (item.Value.ToString() == _idvalue.ToString())
                                    {
                                        item.Selected = true;
                                    }
                                }
                            }
                        }
                    }
                }
                if (control is TextBox)
                {
                    ((TextBox)control).Text = GetFormattedValue(_value);
                }
                if (control is HiddenField)
                {
                    ((HiddenField)control).Value = GetFormattedValue(_value);
                }
                if (control is Label)
                {
                    ((Label)control).Text = GetFormattedValue(_value);
                }
                if (control is CheckBox)
                {
                    String strValue = GetFormattedValue(_value);
                    ((CheckBox)control).Checked = strValue.Equals("True", StringComparison.OrdinalIgnoreCase)
                        || strValue.Equals("S", StringComparison.OrdinalIgnoreCase)
                        || strValue.Equals("Y", StringComparison.OrdinalIgnoreCase);
                }
            }
        }

        /// <summary>
        /// Fill the Object with corresponding property
        /// </summary>
        /// <param name="control"></param>
        /// <param name="TheObject"></param>
        /// <param name="PropertyName"></param>
        protected void FillObjectProperty(Control control, T TheObject, string PropertyName)
        {
            object _value = null;
            PropertyInfo propInfo = null;
            foreach (PropertyInfo prp in TheObject.GetType().GetProperties())
            {
                if (PropertyName.Equals(prp.Name, StringComparison.OrdinalIgnoreCase))
                {
                    propInfo = prp;
                    break;
                }
            }
            if (control is DropDownList)
            {
                foreach (ListItem item in ((DropDownList)control).Items)
                {
                    if (item.Selected)
                    {
                        _value = SetFormattedValue(item.Value, propInfo);
                        break;
                    }
                }
            }
            if (control is TextBox)
            {
                _value = SetFormattedValue(((TextBox)control).Text, propInfo);
            }
            if (control is HiddenField)
            {
                _value = SetFormattedValue(((HiddenField)control).Value, propInfo);
            }
            if (control is Label)
            {
                _value = SetFormattedValue(((Label)control).Text, propInfo);
            }
            //if (control is CheckBox)
            //{
            //    _value = SetFormattedValue(((CheckBox)control).Checked, propInfo);
            //}

            foreach (object attr in propInfo.PropertyType.GetCustomAttributes(typeof(Table), true))
            {
                object FK = TheObject.GetType().InvokeMember(PropertyName,
                    BindingFlags.GetProperty, null, TheObject, null);
                if (FK == null && Convert.ToString(_value) != "")
                {
                    FK = Activator.CreateInstance(propInfo.PropertyType);
                    TheObject.GetType().InvokeMember(PropertyName,
                        BindingFlags.SetProperty, null, TheObject, new object[] { FK });
                }
                if (FK != null)
                {
                    foreach (PropertyInfo info in FK.GetType().GetProperties())
                    {
                        foreach (object attrC in info.GetCustomAttributes(typeof(Id), true))
                        {
                            _value = SetFormattedValue((string)_value, info);
                            if (Convert.ToString(_value) != "")
                            {
                                FK.GetType().InvokeMember(info.Name, BindingFlags.SetProperty, null, FK, new object[] { _value });
                                return;
                            }
                            else
                            {
                                return;
                            }
                        }
                    }
                }
                else
                {
                    return;
                }
            }
            TheObject.GetType().InvokeMember(PropertyName,
                BindingFlags.SetProperty, null, TheObject, new object[] { _value });
        }

        /// <summary>
        /// Sets the value based on type
        /// </summary>
        /// <param name="_value"></param>
        /// <param name="propInfo"></param>
        /// <returns></returns>
        protected object SetFormattedValue(string _value, PropertyInfo propInfo)
        {
            try
            {
                if (propInfo.PropertyType.ToString() == typeof(DateTime).ToString() ||
                    propInfo.PropertyType.ToString() == typeof(DateTime?).ToString())
                {
                    return DateTime.Parse(_value);
                }
                if (propInfo.PropertyType.ToString() == typeof(float).ToString() ||
                    propInfo.PropertyType.ToString() == typeof(float?).ToString())
                {
                    return float.Parse(_value);
                }
                if (propInfo.PropertyType.ToString() == typeof(double).ToString() ||
                    propInfo.PropertyType.ToString() == typeof(double?).ToString())
                {
                    return double.Parse(_value);
                }
                if (propInfo.PropertyType.ToString() == typeof(decimal).ToString() ||
                    propInfo.PropertyType.ToString() == typeof(decimal?).ToString())
                {
                    return decimal.Parse(_value);
                }
                if (propInfo.PropertyType.ToString() == typeof(Int16).ToString() ||
                    propInfo.PropertyType.ToString() == typeof(Int16?).ToString())
                {
                    return Int16.Parse(_value);
                }
                if (propInfo.PropertyType.ToString() == typeof(Int32).ToString() ||
                    propInfo.PropertyType.ToString() == typeof(Int32?).ToString())
                {
                    return Int32.Parse(_value);
                }
                if (propInfo.PropertyType.ToString() == typeof(Int64).ToString() ||
                    propInfo.PropertyType.ToString() == typeof(Int64?).ToString())
                {
                    return Int64.Parse(_value);
                }
            }
            catch
            {
                return null;
            }
            return _value;
        }


        /// <summary>
        /// Fill a new object based on Page Controls
        /// </summary>
        /// <param name="_page">The Page Context</param>
        /// <returns>New instance of the Object</returns>
        public T FillObject(Page _page)
        {
            return FillObject(_page, "", "");
        }

        /// <summary>
        /// Fill a new object based on Page Controls
        /// </summary>
        /// <param name="_page">The Page Context</param>
        /// <param name="ConnectionString">Connection String used to provide the OnDemmand Functionality</param>
        /// <param name="ProviderName">Provider Name used to provide the OnDemmand Functionality</param>
        /// <param name="DatabaseType">Database Type used to provide the OnDemmand Functionality</param>
        /// <returns>New instance of the Object</returns>
        public T FillObject(Page _page, string ConnectionString, string ProviderName)
        {
            T NewObject = (T)NormalProxy.CreateProxy(Activator.CreateInstance(typeof(T)), ConnectionString, ProviderName);
            List<Control> lstControls = new List<Control>();
            GetElegibleFields(lstControls, _page.Controls);
            foreach (PropertyInfo Info in NewObject.GetType().GetProperties())
            {
                foreach (object attr in Info.GetCustomAttributes(typeof(Id), true))
                {
                    foreach (Control control in lstControls)
                    {
                        if (Info.Name.Equals(control.ID, StringComparison.OrdinalIgnoreCase))
                        {
                            FillObjectProperty(control, NewObject, Info.Name);
                        }
                    }
                }
                foreach (object attr in Info.GetCustomAttributes(typeof(Column), true))
                {
                    foreach (Control control in lstControls)
                    {
                        if (Info.Name.Equals(control.ID, StringComparison.OrdinalIgnoreCase))
                        {
                            FillObjectProperty(control, NewObject, Info.Name);
                        }
                    }
                }
            }
            return NewObject;
        }

        /// <summary>
        /// Get the elegible controls to be able to use to fill the properties
        /// </summary>
        /// <param name="lstControls">The list of controls to be filled</param>
        /// <param name="Controls">The Control Collection derived by page</param>
        protected void GetElegibleFields(List<Control> lstControls, ControlCollection Controls)
        {
            foreach (Control control in Controls)
            {
                if (control is TextBox || control is DropDownList ||
                    control is CheckBoxList || control is Label ||
                    control is HiddenField || control is GridView ||
                    control is CheckBox)
                {
                    lstControls.Add(control);
                }
                GetElegibleFields(lstControls, control.Controls);
            }
        }

        /// <summary>
        /// Gets the list of RequiredValidators to activate in case of required fields
        /// </summary>
        /// <param name="validators"></param>
        /// <param name="Controls"></param>
        protected void GetValidators(List<RequiredFieldValidator> validators, ControlCollection Controls)
        {
            foreach (Control control in Controls)
            {
                if (control is RequiredFieldValidator)
                {
                    validators.Add((RequiredFieldValidator)control);
                }
                GetValidators(validators, control.Controls);
            }
        }

        /// <summary>
        /// Formats the value based on type and current cultureinfo
        /// </summary>
        /// <param name="_value"></param>
        /// <returns></returns>
        protected String GetFormattedValue(object _value)
        {
            if (_value is DateTime)
            {
                DateTime dt = DateTime.MinValue;
                if (DateTime.TryParse(Convert.ToString(_value), out dt))
                {
                    return dt.ToString(DateFormat);
                }
            }
            if (_value is Single)
            {
                float fl = 0;
                if (float.TryParse(Convert.ToString(_value), out fl))
                {
                    return fl.ToString(NumberFormat);
                }
            }
            if (_value is Double)
            {
                double dbl = 0;
                if (double.TryParse(Convert.ToString(_value), out dbl))
                {
                    return dbl.ToString(NumberFormat);
                }
            }
            if (_value is Decimal)
            {
                decimal dec = 0;
                if (decimal.TryParse(Convert.ToString(_value), out dec))
                {
                    return dec.ToString(NumberFormat);
                }
            }
            return Convert.ToString(_value);
        }
    }
}